// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: jhkim

#pragma once
#include <experimental/filesystem>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>
#include <set>

#include "coin2/exchange/base/feed/ws/ws_subscriber_util.h"
#include "coin2/exchange/base/market/market_exchange_api.h"

namespace impl {

using coin2::exchange::base::market::MarketExchangeApi;

struct FeedRecipeSpec {
  MarketExchangeApiRecipe mear;
  // e.g. [trade, bbo]
  std::set<std::string> channels;
};

class FeedRecipeSpecMap {
 public:
  static FeedRecipeSpecMap FromToml(
      const std::experimental::filesystem::path& path) {
    FeedRecipeSpecMap map;
    const auto table = toml::parse(path).as_table();

    /*
    [[spot_okex_v3]]
    recipe.snapshot = ["trade", "depth200"]
    */

    for (auto& pair : table) {
      MarketExchangeApi mea = MarketExchangeApi::FromSnakeString(pair.first);
      auto& recipe_tables = pair.second.as_table().at("recipe").as_table();
      for (auto& recipe_kv : recipe_tables) {
        FeedRecipeSpec spec;
        spec.mear = MarketExchangeApiRecipe{mea, recipe_kv.first};
        for (auto& channel_iter : recipe_kv.second.as_array()) {
          spec.channels.insert(channel_iter.as_string());
        }
        map.map_[spec.mear] = spec;
      }
    }
    return map;
  }

  bool Has(const MarketExchangeApiRecipe& mear) const {
    return map_.count(mear) > 0;
  }

  const FeedRecipeSpec& At(const MarketExchangeApiRecipe& mear) const {
    if (map_.count(mear) == 0) {
      THROW() << "Cannot find subscriber spec for " << mear.String();
    }
    return map_.at(mear);
  }

 private:
  std::unordered_map<MarketExchangeApiRecipe, FeedRecipeSpec> map_;
};

}  // namespace impl

using impl::FeedRecipeSpec;
using impl::FeedRecipeSpecMap;
